#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>


typedef struct _st_sm2_key
{
    uint8_t priKey[32];
    uint8_t pubKey[65];
}SM2_KEY;

typedef struct _st_sm2_encrypt
{
    uint8_t M[256];
    uint32_t MByteLen;
    uint8_t pubKey[65];
    uint8_t order;
    uint8_t C[512];
    uint32_t CByteLen;
}SM2_ENCRYPT;

typedef struct _st_sm2_decrypt
{
    uint8_t C[512];
    uint32_t CByteLen;
    uint8_t priKey[32];
    uint8_t order;
    uint8_t M[256];
    uint32_t MByteLen;
}SM2_DECRYPT;

typedef struct _st_sm2_getZ
{
    uint8_t ID[1024];
    uint32_t byteLenofID;
    uint8_t pubKey[65];
    uint8_t Z[32];
}SM2_GETZ;

typedef struct _st_sm2_getE
{
    uint8_t M[128];
    uint32_t byteLen;
    uint8_t Z[32];
    uint8_t E[32];
}SM2_GETE;

typedef struct _st_sm2_sign
{
    uint8_t E[32];
    uint8_t priKey[32];
    uint8_t signature[64];
}SM2_SIGN;

typedef struct _st_sm2_verify
{
    uint8_t E[32];
    uint8_t pubKey[65];
    uint8_t signature[64];
}SM2_VERIFY;


#define SCTO_SM2_KEYGET            _IOR('k', 0, SM2_KEY *)
#define SCTO_SM2_ENCRYPT           _IOR('k', 1, SM2_ENCRYPT *)
#define SCTO_SM2_DECRYPT           _IOR('k', 2, SM2_DECRYPT *)
#define SCTO_SM2_GETZ              _IOR('k', 3, SM2_GETZ *)
#define SCTO_SM2_GETE              _IOR('k', 4, SM2_GETE *)
#define SCTO_SM2_SIGN              _IOR('k', 5, SM2_SIGN *)
#define SCTO_SM2_VERIFY            _IOR('k', 6, SM2_VERIFY *)





int main(int argc, char **argv)
{
    int fd = open("/dev/dma", O_RDWR);
    if( fd < 0 ){
        printf("open /dev/dma failed\n");
        return -1;
    }
    int k;
    int ret = 0;

    SM2_KEY val, val1;
    ret = ioctl(fd, SCTO_SM2_KEYGET, &val);
    if( ret != 0 ){
        printf("SCTO_SM2_KEYGET failed with ret:%d\n",ret);
        close(fd);
        return -1; 
    }

    ret = ioctl(fd, SCTO_SM2_KEYGET, &val1);
    if( ret != 0 ){
        printf("SCTO_SM2_KEYGET failed with ret:%d\n",ret);
        close(fd);
        return -1; 
    }

    FILE *fp;

    if( (fp=fopen("./temp/A.priKey", "wb")) == NULL ){  //以二进制方式打开
        puts("Fail to open file!");
        exit(0);
    }

    fwrite(val.priKey, 1, 32, fp);
    fclose(fp);

    if( (fp=fopen("./temp/A.pubKey", "wb")) == NULL ){  //以二进制方式打开
        puts("Fail to open file!");
        exit(0);
    }

    fwrite(val.pubKey, 1, 65, fp);
    fclose(fp);

    if( (fp=fopen("./temp/B.priKey", "wb")) == NULL ){  //以二进制方式打开
        puts("Fail to open file!");
        exit(0);
    }

    fwrite(val1.priKey, 1, 32, fp);
    fclose(fp);

    if( (fp=fopen("./temp/B.pubKey", "wb")) == NULL ){  //以二进制方式打开
        puts("Fail to open file!");
        exit(0);
    }

    fwrite(val1.pubKey, 1, 65, fp);
    fclose(fp);


    printf("Key pair of A:\n");
    for (int i = 0; i < 32; i++){
        printf("%02x", val.priKey[i]);
    }

    printf("\n");

    for (int i = 0; i < 65; i++){
        printf("%02x", val.pubKey[i]);
    }
    printf("\n");

    printf("Key pair of B:\n");
    for (int i = 0; i < 32; i++){
        printf("%02x", val1.priKey[i]);
    }

    printf("\n");

    for (int i = 0; i < 65; i++){
        printf("%02x", val1.pubKey[i]);
    }
    printf("\n");


    //encrypt
    //sm2_encrypt.M 最多415个字节，否则解密会失败。
    uint8_t *temp_data;

    if( (fp=fopen("plaintext", "rb")) == NULL ){  //以二进制方式打开
        puts("Fail to open plaintext!");
        return -1;
    }
    fseek(fp, 0, SEEK_END);        //指针：移动到文件尾部
    uint32_t f_size = ftell(fp);   //返回指针偏离文件头的位置（即文件中字符个数）
    temp_data = (uint8_t *)malloc(sizeof(uint8_t)*(f_size));
    memset(temp_data, 0, f_size);
    fseek(fp, 0, SEEK_SET);  //指针：移动到文件头部
    fread(temp_data, 1, f_size, fp);
    fclose(fp);

    SM2_ENCRYPT sm2_encrypt;
    memset(&sm2_encrypt, 0, sizeof(sm2_encrypt));
    memcpy(sm2_encrypt.M, temp_data, f_size);
    sm2_encrypt.MByteLen =f_size;
    memcpy(sm2_encrypt.pubKey, val1.pubKey, sizeof(val1.pubKey));
    sm2_encrypt.order = 0;

    ret = ioctl(fd, SCTO_SM2_ENCRYPT, &sm2_encrypt);
    if( ret != 0 ){
        printf("SCTO_SM2_ENCRYPT failed with ret:%d\n",ret);
        close(fd);
        return -1; 
    }
    printf("%d\n", sm2_encrypt.CByteLen);

    if( (fp=fopen("ciphertext", "rb")) == NULL ){  //以二进制方式打开
        puts("Fail to open ciphertext!");
        return -1;
    }
    fwrite(sm2_encrypt.C, 1, sm2_encrypt.CByteLen, fp);
    fclose(fp);
    
    //decrypt
    
    SM2_DECRYPT sm2_decrypt;
    memset(&sm2_decrypt, 0, sizeof(sm2_decrypt));
    memcpy(sm2_decrypt.C, sm2_encrypt.C, sm2_encrypt.CByteLen);
    sm2_decrypt.CByteLen = sm2_encrypt.CByteLen;
    memcpy(sm2_decrypt.priKey, val1.priKey, sizeof(val1.priKey));
    sm2_decrypt.order = 0;
    ret = ioctl(fd, SCTO_SM2_DECRYPT, &sm2_decrypt); 
    if( ret != 0 ){
        printf("SCTO_SM2_DECRYPT failed with ret:%d\n",ret);
        close(fd);
        return -1; 
    }
    //printf("M:%s\n",sm2_decrypt.M);

    

    printf("M:\n");
    for (int i = 0; i < 65; i++){
        printf("%02x", sm2_decrypt.M[i]);
    }
    printf("\n");
    

    close(fd);
    return 0;
}